package lmscript.postscript.io;

import java.io.IOException;
import java.io.OutputStream;

public class ASCII85OutputStream extends OutputStream implements ASCII85 {

	private OutputStream out;
	private int[] b4 = new int[4];
	private int[] c5 = new int[5];
	private int bIndex = 0;
	private int written = 0;

	public ASCII85OutputStream(OutputStream out) {
		this.out = out;
	}

	@Override
	public void write(int b) throws IOException {
		b4[bIndex] = b & 0xFF;
		if (bIndex == 4) {
			writeTuple();
			b4[0] = b4[1] = b4[2] = b4[3] = 0;
			bIndex = 0;
		}
	}

	private void writeTuple() throws IOException {
		long d = (b4[0] << 24 + b4[1] << 16 + b4[2] << 8 + b4[3]) & 0xFFFFFFFFL;

		c5[0] = (int) (d / a85p4 + '!');
		d %= a85p4;
		c5[1] = (int) (d / a85p3 + '!');
		d %= a85p3;
		c5[2] = (int) (d / a85p2 + '!');
		d %= a85p2;
		c5[3] = (int) (d / a85p1 + '!');
		d %= a85p1;
		c5[4] = (int) (d + '!');

		if (c5[0] == '!' && c5[1] == '!' && c5[2] == '!' && c5[3] == '!' && c5[4] == '!') {
			writeChar('z');
		} else {
			writeChar(c5[0]);
			writeChar(c5[1]);
			writeChar(c5[2]);
			writeChar(c5[3]);
			writeChar(c5[4]);
		}
	}

	private void writeChar(int c) throws IOException {
		if (written >= MAX_CHARS_PER_LINE) {
			this.out.write('\n');
			written = 0;
		}
		written++;
		this.write(c);
	}

	public void finish() throws IOException {
		writeChar('>');
		out.flush();
	}

	public void close() throws IOException {
		finish();
		out.close();
	}
}
